//
// Created by wxd on 2025/7/23.
//

#pragma once

#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#include <glm/trigonometric.hpp>
#include "../wrapper/log/Logger.h"
#include "../wrapper/monitor/GLDebug.hpp"
#include "../global/ChineseOutput.hpp"
#include "../global/EngineDataProperties.h"
#include "../application/app/Application.h"
#include "../glFramework/shader/Shader.h"
#include "../glFramework/constant/engine_layout.h"
#include "../glFramework/texture/Texture.h"
#include "../glFramework/utils/ResourceLoadUtils.h"
#include "../glFramework/bo/VBO.h"
#include "../glFramework/bo/VAO.h"
#include "../glFramework/constant/engine_uniform.h"
#include <memory>

#include "bo/EBO.h"
#include "../global/output.hpp"

struct Camera {
    glm::vec3 eye;
    glm::vec3 center;
    glm::vec3 up;
    glm::mat4 viewMatrix;

    void setEye(glm::vec3 eye) {
        this->eye = eye;
    }

    void setCenter(glm::vec3 center) {
        this->center = center;
    }

    void setUp(glm::vec3 up) {
        this->up = up;
    }

    void update() {
        viewMatrix = glm::lookAt(eye, center, up);
    }

    Camera() {
        eye = glm::vec3(0.f, 0.f, 0.5f);
        center = glm::vec3(0.f);
        up = glm::vec3(0.f, 1.f, 0.0f);
        viewMatrix = glm::lookAt(eye, center, up);
    }

    Camera(glm::vec3 eye, glm::vec3 center, glm::vec3 up) : eye(eye), center(center), up(up) {
        viewMatrix = glm::lookAt(eye, center, up);
    }
};

inline float angleSpeed = 25.0f; // 25度每秒
inline float accAngle = 0.f;
inline float lastFrame = 0.f;
inline float currFrame = 0.f;
inline float deltaFrame = 0.f;

inline const char* vertexPath = "../demo/shader/_010/vertex_shader.glsl";
inline const char* fragmentPath = "../demo/shader/_010/fragment_shader.glsl";
inline const char* texPath = "../demo/texture/earth.png";

inline glm::mat4 modelMatrix = glm::mat4(1.0f);
inline Camera camera(glm::vec3(0.f, 0.f, 1.0f), glm::vec3(0.0f), glm::vec3(0.f, 1.f, 0.f));

inline void onResize(int w, int h) {
    glViewport(0, 0, w, h);
}

inline void onKeyBoard(int key, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE) {
        glfwSetWindowShouldClose(EngineApp.getCurrentWindow(), true);
    } else if (key == GLFW_KEY_W) {
    } else if (key == GLFW_KEY_S) {
    }
}

inline void render() {
    ChineseOutput::init();
    EngineApp.initDefaultWindowConfig();
    EngineApp.setResizeCallback(onResize);
    EngineApp.setKeyBoardCallback(onKeyBoard);
    EngineApp.init();

    std::vector<float> vertices;
    vertices.reserve(32); // 顶点坐标 + 颜色 + 纹理坐标
    std::vector<unsigned int> indices;
    indices.reserve(6);

    vertices.push_back(0.5f);
    vertices.push_back(0.5f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.5f);
    vertices.push_back(-0.5f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(-0.5f);
    vertices.push_back(-0.5f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(-0.5f);
    vertices.push_back(0.5f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(0.0f);
    vertices.push_back(1.0f);

    indices.push_back(0);
    indices.push_back(1);
    indices.push_back(2);
    indices.push_back(0);
    indices.push_back(2);
    indices.push_back(3);

    Texture texture(texPath);
    texture.setSamplerName(EngineUniform::uTexUnit);

    VAO vao;
    vao.bind();
    VBO vbo(vertices);
    EBO ebo(indices);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, fSize(8), reinterpret_cast<void *>(0));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, fSize(8), reinterpret_cast<void *>(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, fSize(8), reinterpret_cast<void *>(6 * sizeof(float)));
    glEnableVertexAttribArray(2);
    vao.unbind();

    std::unique_ptr<Shader> shader = std::make_unique<Shader>(vertexPath, fragmentPath);

    std::string uw = "uW";
    std::string uH = "uH";
    std::string uTexUnit = "uTexUnit";
    std::string uModel = "uModel";
    std::string uView = "uView";


    // 由于这里还没有引入投影矩阵，导致目前相机绕着原点的模型坐圆周运动的时候，由于视角发生了改变，会会导致正方形在渲染过程中发生变形
    while (EngineApp.update()) {
        GL_CALL(glClear(GL_COLOR_BUFFER_BIT))

        shader->bindProgram();
        shader->setUniform(uModel, modelMatrix);
        shader->setUniform(uView, camera.viewMatrix);
        shader->setUniform(EngineUniform::uW, static_cast<float>(EngineApp.getCurrentWindowWidth()));
        shader->setUniform(EngineUniform::uH, static_cast<float>(EngineApp.getCurrentWindowHeight()));
        shader->setUniform(texture.getSamplerName(), texture.getTextureUnit()); // 采样0号单元

        currFrame = static_cast<float>(glfwGetTime());
        if (lastFrame > 0.f) {
            deltaFrame = currFrame - lastFrame;
        }
        lastFrame = currFrame;

        accAngle += deltaFrame * angleSpeed;
        if (accAngle > 360.0f) {
            accAngle -= 360.f;
        }
        float x = glm::sin(glm::radians(accAngle));
        float z = glm::cos(glm::radians(accAngle));
        camera.eye.x = x;
        camera.eye.z = z;
        camera.update();

        vao.bind();
        GL_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, reinterpret_cast<void*>(0)))
        vao.unbind();
        shader->unbindProgram();
    }

    EngineApp.destroy();
}
